package com.newlandedu.antchainvote.antchain.config;

import com.alipay.mychain.sdk.api.MychainClient;
import com.alipay.mychain.sdk.api.env.ClientEnv;
import com.alipay.mychain.sdk.api.env.ISslOption;
import com.alipay.mychain.sdk.api.env.SignerOption;
import com.alipay.mychain.sdk.api.env.SslBytesOption;
import com.alipay.mychain.sdk.api.logging.AbstractLoggerFactory;
import com.alipay.mychain.sdk.api.logging.ILogger;
import com.alipay.mychain.sdk.api.utils.Utils;
import com.alipay.mychain.sdk.crypto.MyCrypto;
import com.alipay.mychain.sdk.crypto.keyoperator.Pkcs8KeyOperator;
import com.alipay.mychain.sdk.crypto.keypair.Keypair;
import com.alipay.mychain.sdk.crypto.signer.SignerBase;
import com.alipay.mychain.sdk.domain.account.Identity;
import com.alipay.mychain.sdk.utils.IOUtil;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

/**
 * 用途
 *
 * @author deng
 * @date 2020/11/12 17:04
 */

@Configuration
@ConfigurationProperties(prefix = "antchain")
public class AntChainConfig {
    private static ILogger logger = AbstractLoggerFactory.getInstance(AntChainConfig.class);
    /**
     * baas上创建的帐户名字
     */
    private String account;//TODO 需要修改成自己账户

    /**
     * sdk client
     */
    public MychainClient sdk;
    /**
     * client key password
     */
    private String keyPassword; //TODO 申请证书时候指定的SSL密码

    /**
     * user password
     */
    private String userPassword; //TODO 根据实际情况更新。申请证书时，创建账户的密码


    /**
     * host ip
     */
    /**
     * 节点名称
     * 节点高度
     * 运行状态
     * 47.103.163.178 18130 10477350
     * 47.103.163.48 18130  10477350
     * 106.14.168.236 18130 10477349
     * 47.102.11.238 18130  10477350
     */

    private String host; //根据实际情况更新，在BaaS平台，通过查看目标合约链"详情"，在"浏览器"中查看"节点详情"可获取链节点的 IP地址 和 端口号。

    /**
     * trustCa password.
     */
    private String trustStorePassword;

    /**
     * server port
     */
    private int port;               //端口默认为18130 根据实际情况更新


    /**
     * mychain environment
     */
    private static ClientEnv env;

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getKeyPassword() {
        return keyPassword;
    }

    public void setKeyPassword(String keyPassword) {
        this.keyPassword = keyPassword;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getTrustStorePassword() {
        return trustStorePassword;
    }

    public void setTrustStorePassword(String trustStorePassword) {
        this.trustStorePassword = trustStorePassword;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    /**
     * tee chain publicKeys
     */
    private static List<byte[]> publicKeys = new ArrayList<byte[]>();


    public Identity userIdentity;
    private Keypair userKeypair;

    @PostConstruct
    public void init() throws IOException {

        initMychainEnv();

        //step 2: init sdk client
        initSdk();
    }

    @PreDestroy
    public void close() {
        //step 6 : sdk shut down
        sdk.shutDown();
    }

    private void initMychainEnv() throws IOException {
        // any user key for sign message
        String userPrivateKeyFile = "user.key";
        userIdentity = Utils.getIdentityByName(account);
        Pkcs8KeyOperator pkcs8KeyOperator = new Pkcs8KeyOperator();
        userKeypair = pkcs8KeyOperator.load(IOUtil.inputStreamToByte(this.getClass().getClassLoader().getResourceAsStream(userPrivateKeyFile)), userPassword);

        env = buildMychainEnv();
        env.setLogger(logger);
    }

    private ClientEnv buildMychainEnv() throws IOException {
        InetSocketAddress inetSocketAddress = InetSocketAddress.createUnresolved(host, port);
        String keyFilePath = "client.key";
        String certFilePath = "client.crt";
        String trustStoreFilePath = "trustCa";

        // build ssl option
        ISslOption sslOption = new SslBytesOption.Builder()
                .keyBytes(IOUtil.inputStreamToByte(this.getClass().getClassLoader().getResourceAsStream(keyFilePath)))
                .certBytes(IOUtil.inputStreamToByte(this.getClass().getClassLoader().getResourceAsStream(certFilePath)))
                .keyPassword(keyPassword)
                .trustStorePassword(trustStorePassword)
                .trustStoreBytes(
                        IOUtil.inputStreamToByte(this.getClass().getClassLoader().getResourceAsStream(trustStoreFilePath)))
                .build();

        List<InetSocketAddress> socketAddressArrayList = new ArrayList<InetSocketAddress>();
        socketAddressArrayList.add(inetSocketAddress);

        List<SignerBase> signerBaseList = new ArrayList<SignerBase>();
        SignerBase signerBase = MyCrypto.getInstance().createSigner(userKeypair);
        signerBaseList.add(signerBase);
        SignerOption signerOption = new SignerOption();
        signerOption.setSigners(signerBaseList);

        return ClientEnv.build(socketAddressArrayList, sslOption, signerOption);
    }

    private void initSdk() {
        sdk = new MychainClient();
        boolean initResult = sdk.init(env);
        if (!initResult) {
            exit("initSdk", "sdk init failed.");
        } else {
            logger.info("sdk init success");
        }
    }

    private static void exit(String msg) {
        logger.error(msg);
        System.exit(0);
    }

    private static void exit(String tag, String msg) {
        exit(String.format("%s error : %s ", tag, msg));
    }


}
